/* -*-  Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
  //
// Copyright (c) 2006 Georgia Tech Research Corporation
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation;
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
// Author: George F. Riley<riley@ece.gatech.edu>
//

// ns3 - On/Off Data Source Application class
// George F. Riley, Georgia Tech, Spring 2007
// Adapted from ApplicationFlow in GTNetS.

#include "flow-server.h"
#include "flow-server-application.h"

NS_LOG_COMPONENT_DEFINE ("FlowServerApplication");

using namespace std;

namespace ns3 {

NS_OBJECT_ENSURE_REGISTERED (FlowServerApplication);
 
TypeId
FlowServerApplication::GetTypeId (void)
{
  static TypeId tid = TypeId ("ns3::FlowServerApplication")
    .SetParent<Application> ()
    .AddConstructor<FlowServerApplication> ()
    .AddAttribute ("Local", "The Address on which to Bind the rx socket.",
                   AddressValue (),
                   MakeAddressAccessor (&FlowServerApplication::m_local),
                   MakeAddressChecker ())             
       ;
  return tid;
}

FlowServerApplication::FlowServerApplication ()
{
  NS_LOG_FUNCTION_NOARGS ();
}

FlowServerApplication::~FlowServerApplication()
{
  NS_LOG_FUNCTION_NOARGS ();
}


void
FlowServerApplication::DoDispose (void)
{
  NS_LOG_FUNCTION_NOARGS ();

  // chain up
  Application::DoDispose ();
}

// Application Methods
void 
FlowServerApplication::StartApplication() // Called at time specified by Start
{
  NS_LOG_FUNCTION (this);

  // listening socket 
  if ( !m_socket && !m_local.IsInvalid() )
  {
    NS_LOG_LOGIC ("creating listening socket " << m_local);
    m_socket = Socket::CreateSocket (GetNode(), TcpSocketFactory::GetTypeId());
    m_socket->Bind (m_local);
    m_socket->Listen ();

    m_socket->SetAcceptCallback (
            MakeNullCallback<bool, Ptr<Socket>, const Address &> (),
            MakeCallback(&FlowServerApplication::HandleAccept, this));
  }
}    

void 
FlowServerApplication::StopApplication() // Called at time specified by Stop
{
  NS_LOG_FUNCTION_NOARGS ();

  //for server, stop accepting new flows
  if( m_socket )
  {
    m_socket->Close();
    m_socket = 0;
  }                                
  
  // ...and opened sockets
  while(!m_flowList.empty()) 
  {
    Ptr<FlowServer> server = m_flowList.front(); 
    server->Stop();
    m_flowList.pop_front();
  }  
}

void 
FlowServerApplication::HandleAccept (Ptr<Socket> s, const Address& from)
{
  NS_LOG_FUNCTION (this << s << from);
  //create Flow server
  Ptr<FlowServer> server = CreateObject<FlowServer> (s);
  server->SetFlowFinishCallback(MakeCallback(&FlowServerApplication::HandleFlowFinish, this));
  m_flowList.push_back (server);
}

void 
FlowServerApplication::HandleFlowFinish (Ptr<FlowServer> flow)
{
  NS_LOG_FUNCTION (this << flow << flow->GetSize() << flow->GetDuration() );
  // log stats

  //destroy flow
  m_flowList.remove (flow);
}

} // Namespace ns3
